接下來介紹「刪除英雄」的實作方法。
我規劃是在每個項目後面增加一個刪除按鈕,按下該按鈕就刪除該項目,簡單明確。
首先要調整 Listbox 中的範本:
<listbox id="heroBox" rows="5" emptyMessage="無資料" nonselectableTags="">
<listhead>
<listheader width="50px"/>
<listheader width="50%"/>
<listheader/>
</listhead>
<template name="model">
<listitem>
<listcell label="${forEachStatus.index}"/>
<listcell label="${each.name}"/>
<listcell style="text-align:right">
<button iconSclass="z-icon-times" forward="heroBox.onDelete"/>
</listcell>
</listitem>
</template>
</listbox>
<listheader>
,範本中第三個 <listcell>
增加一個按鈕,并加上一個 X 圖示,代表刪除。<listcell>
可以內包任何元件。nonselectableTags=""
,就代表不管點listitem 內的任一元件,就會同時選取該 listitem,這會讓我知道使用者到底點的是哪個listitem 內的刪除按鈕forward
那一行代表的意義是:將 onClick
事件轉發成 onDelete
事件到 heroBox
上,這個原因是跟傾聽器綁定的時間點有關,我會在下一節說明。假如按照我之前介紹的觀念,傾聽刪除按鈕的作法是@Listen("onClick = listcell > button")
但其實行不通,理由請看以下程式碼:
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
//在此初始化資料或元件
heroList.addAll(HeroService.getInitHero());
heroBox.setModel(heroList);
}
@Listen
是由 SelectorComposer
來幫你基於該 annotation 註冊傾聽器,是在super.doAfterCompose(comp)
內執行,但是 listbox 直到 setModel()
才根據該 data model 建立對應的 listitem,也就是要註冊傾聽器的時機時,目標 button都還沒產生,根本無法註冊還不存在的元件上,因此要換個做法。
因此利用 ZK 另一個特性「轉發事件」,將 button onClick
事件轉發到父元件 heroBox
上,而轉發的時候可以自訂事件名稱,讓轉發後的事件跟ZK預設事件名稱區隔開來,也有利於辨識,因此我才改轉發成 onDelete
事件,語法如下:
[原事件]=[元件ID].[新事件]
而原事件如果是 onClick
可以省略,因此就可以寫成:
<button iconSclass="z-icon-times" forward="heroBox.onDelete"/>
因此,當使用者點下按鈕,ZK 就會轉發成 onDelete 事件到 heroBox
上。而 heroBox
是先於綁定傾聽器前生成的,因此我可以註冊傾聽器在上面:
@Listen("onDelete = #heroBox")
public void delete(){
heroList.remove(heroList.getSelection().iterator().next());
}
delete()
heroList.getSelection().iterator().next()
就能取得被選擇的 Hero
物件remove()
將該 Hero
移除,依照先前所提過的 model-driven rendering,ListModelList
會發事件通知 Listbox 把這變動的資料繪製到瀏覽器上,因此你會看到被選的英雄就消失了即便不是動態產生的元件,也可以用轉發事件,它能讓你把子元件的的事件都轉發到同一個父元件上,讓你可以一致地註冊傾聽器在該父元件上,不用根據不同動作註冊在不同元件上,一但未來想要變動子元件,只要轉發的事件維持相同,也不需要更改註冊的方式。再來你可以將事件名稱 (event name) 改成更符合應用情境的名稱 (onDelete, onProjectClose) 增加可讀性、可維護性。
刪除功能的實作與新增類似,都是傾聽事件之後,修改 ListModelList
來更新頁面。這也是 ZK 的主要強項,讓你專注在後端的邏輯,跟前端的溝通與重繪都由 ZK 幫你處理了。
以上描述的作法只是其一,你也可以把刪除按鈕拿出 <listbox>
外,等使用者選了一個英雄後再啟用,這樣就不需要轉發事件。